package swing.ui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.Icon;
import javax.swing.JCheckBox;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ActionMapUIResource;


@SuppressWarnings("serial")
public class TristateCheckBox extends JCheckBox {
	

	public static final int NOT_SELECTED = 0;
	public static final int SELECTED = 1;
	public static final int HALF_SELECTED = 2;
	
	private final TristateDecorator model;
	
	public TristateCheckBox(String text, Icon icon, int initial){
		super(text, icon);
		
		super.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				grabFocus();
				model.nextState();
			}
		});
		
	    ActionMap map = new ActionMapUIResource();
		map.put("pressed", new AbstractAction() { //$NON-NLS-1$
			public void actionPerformed(ActionEvent e) {
				grabFocus();
				model.nextState();
			}
		});
		
	    map.put("released", null); //$NON-NLS-1$
	    SwingUtilities.replaceUIActionMap(this, map);
	    
	    model = new TristateDecorator(getModel());
	    setModel(model);
	    setState(initial);
	}
   
	public TristateCheckBox(String text, int initial) {
	    this(text, null, initial);
	}
	
	public TristateCheckBox(String text) {
	    this(text, NOT_SELECTED);
	}

	public TristateCheckBox() {
	    this(""); //$NON-NLS-1$
	}
	  
	
	public void setState(int state) { 
		model.setState(state); 
	}
	
	
	public int getState() {
		return model.getState();
	}
	
	public void setChecked(boolean checked) {
		if (checked)
			setState(SELECTED);
		else
			setState(NOT_SELECTED);
	}

	public boolean getChecked() {
		return model.getState() == SELECTED;
	}
	
	
	public void addMouseListener(MouseListener l) {		
	}
	
	private class TristateDecorator implements ButtonModel {
	    
		private final ButtonModel other;
		
	    private TristateDecorator(ButtonModel other) {
			this.other = other;
		}
	    
	    private void setState(int state) {
			if (state == NOT_SELECTED) {
				other.setArmed(false);
				setPressed(false);
				setSelected(false);
			} else if (state == SELECTED) {
				other.setArmed(false);
				setPressed(false);
				setSelected(true);
			} else if (state == HALF_SELECTED) {
				other.setArmed(true);
				setPressed(true);
				setSelected(true);
			}
		}
	    
	  
	    private int getState() {
			if (isSelected() && !isArmed()) {
				return SELECTED;
			} else if (isSelected() && isArmed()) {
				return HALF_SELECTED;
			} else {
				return NOT_SELECTED;
			}
		}
	    
	    
	    private void nextState() {
			int current = getState();
			
			if (current == NOT_SELECTED) {
				setState(SELECTED);
			} else if (current == SELECTED) {
				setState(HALF_SELECTED);
			} else if (current == HALF_SELECTED) {
				setState(NOT_SELECTED);
			}
		}
	    
	    public void setArmed(boolean b) {
		}
	    
	    
	    public void setEnabled(boolean b) {
			setFocusable(b);
			other.setEnabled(b);
		}

	   
	    public boolean isArmed() {
			return other.isArmed();
		}
	    
	    
	    public boolean isSelected() {
			return other.isSelected();
		}
	    
	   
	    public boolean isEnabled() {
			return other.isEnabled();
		}
	   
	    public boolean isPressed() {
			return other.isPressed();
		}
	    
	   
	    public boolean isRollover() {
			return other.isRollover();
		}
	    
	   
	    public void setSelected(boolean b) {
			other.setSelected(b);
		}
	    
	    public void setPressed(boolean b) {
			other.setPressed(b);
		}
	    
	    public void setRollover(boolean b) {
			other.setRollover(b);
		}
	    
	   
	    public void setMnemonic(int key) {
			other.setMnemonic(key);
		}

	    public int getMnemonic() {
			return other.getMnemonic();
		}
	   
	    public void setActionCommand(String s) {
			other.setActionCommand(s);
		}

	    public String getActionCommand() {
			return other.getActionCommand();
		}
	   
	    public void setGroup(ButtonGroup group) {
			other.setGroup(group);
		}

	    public void addActionListener(ActionListener l) {
			other.addActionListener(l);
		}
	    
	   
	    public void removeActionListener(ActionListener l) {
			other.removeActionListener(l);
		}
	   
	    public void addItemListener(ItemListener l) {
			other.addItemListener(l);
		}
	    
	    public void removeItemListener(ItemListener l) {
			other.removeItemListener(l);
		}
	   
	    public void addChangeListener(ChangeListener l) {
			other.addChangeListener(l);
		}

	    public void removeChangeListener(ChangeListener l) {
			other.removeChangeListener(l);
		}
	    public Object[] getSelectedObjects() {
			return other.getSelectedObjects();
		}
	}
}

